using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;

namespace RaisingStudio.SmallBasicCompiler
{
    public class LineScanner
    {
        private int _currentIndex;
        private int _lineLength;
        private string _lineText;
        private char _decimalSeparator = '.';
        public TokenEnumerator GetTokenList(string lineText, int lineNumber)
        {
            if (lineText == null)
            {
                throw new ArgumentNullException("lineText");
            }
            this._lineText = lineText;
            this._lineLength = this._lineText.Length;
            this._currentIndex = 0;
            List<TokenInfo> list = new List<TokenInfo>();
            TokenInfo item;
            while (this.ScanNextToken(out item))
            {
                item.Line = lineNumber;
                list.Add(item);
            }
            return new TokenEnumerator(list)
            {
                LineNumber = lineNumber
            };
        }
        private bool ScanNextToken(out TokenInfo tokenInfo)
        {
            this.EatSpaces();
            tokenInfo = default(TokenInfo);
            tokenInfo.Column = this._currentIndex;
            char nextChar = this.GetNextChar();
            if (nextChar == '\0')
            {
                return false;
            }
            char c = nextChar;
            switch (c)
            {
                case '"':
                    {
                        this._currentIndex--;
                        tokenInfo.Token = Token.StringLiteral;
                        string text = this.ReadStringLiteral();
                        tokenInfo.Text = text;
                        goto IL_387;
                    }
                case '#':
                case '$':
                case '%':
                case '&':
                case '.':
                    {
                        break;
                    }
                case '\'':
                    {
                        this._currentIndex--;
                        tokenInfo.Token = Token.Comment;
                        string text2 = this.ReadComment();
                        tokenInfo.Text = text2;
                        goto IL_387;
                    }
                case '(':
                    {
                        tokenInfo.Token = Token.LeftParens;
                        tokenInfo.Text = "(";
                        goto IL_387;
                    }
                case ')':
                    {
                        tokenInfo.Token = Token.RightParens;
                        tokenInfo.Text = ")";
                        goto IL_387;
                    }
                case '*':
                    {
                        tokenInfo.Token = Token.Multiplication;
                        tokenInfo.Text = "*";
                        goto IL_387;
                    }
                case '+':
                    {
                        tokenInfo.Token = Token.Addition;
                        tokenInfo.Text = "+";
                        goto IL_387;
                    }
                case ',':
                    {
                        tokenInfo.Token = Token.Comma;
                        tokenInfo.Text = ",";
                        goto IL_387;
                    }
                case '-':
                    {
                        tokenInfo.Token = Token.Subtraction;
                        tokenInfo.Text = "-";
                        goto IL_387;
                    }
                case '/':
                    {
                        tokenInfo.Token = Token.Division;
                        tokenInfo.Text = "/";
                        goto IL_387;
                    }
                default:
                    {
                        switch (c)
                        {
                            case ':':
                                {
                                    tokenInfo.Token = Token.Colon;
                                    tokenInfo.Text = ":";
                                    goto IL_387;
                                }
                            case ';':
                                {
                                    break;
                                }
                            case '<':
                                {
                                    nextChar = this.GetNextChar();
                                    if (nextChar == '=')
                                    {
                                        tokenInfo.Token = Token.LessThanEqualTo;
                                        tokenInfo.Text = "<=";
                                        goto IL_387;
                                    }
                                    if (nextChar == '>')
                                    {
                                        tokenInfo.Token = Token.NotEqualTo;
                                        tokenInfo.Text = "<>";
                                        goto IL_387;
                                    }
                                    this._currentIndex--;
                                    tokenInfo.Token = Token.LessThan;
                                    tokenInfo.Text = "<";
                                    goto IL_387;
                                }
                            case '=':
                                {
                                    tokenInfo.Token = Token.Equals;
                                    tokenInfo.Text = "=";
                                    goto IL_387;
                                }
                            case '>':
                                {
                                    nextChar = this.GetNextChar();
                                    if (nextChar == '=')
                                    {
                                        tokenInfo.Token = Token.GreaterThanEqualTo;
                                        tokenInfo.Text = ">=";
                                        goto IL_387;
                                    }
                                    this._currentIndex--;
                                    tokenInfo.Token = Token.GreaterThan;
                                    tokenInfo.Text = ">";
                                    goto IL_387;
                                }
                            default:
                                {
                                    switch (c)
                                    {
                                        case '[':
                                            {
                                                tokenInfo.Token = Token.LeftBracket;
                                                tokenInfo.Text = "[";
                                                goto IL_387;
                                            }
                                        case ']':
                                            {
                                                tokenInfo.Token = Token.RightBracket;
                                                tokenInfo.Text = "]";
                                                goto IL_387;
                                            }
                                    }
                                    break;
                                }
                        }
                        break;
                    }
            }
            char nextChar2 = this.GetNextChar();
            this._currentIndex--;
            if (char.IsLetter(nextChar) || nextChar == '_')
            {
                this._currentIndex--;
                string text3 = this.ReadKeywordOrIdentifier();
                tokenInfo.Token = this.MatchToken(text3);
                tokenInfo.Text = text3;
            }
            else
            {
                if (char.IsDigit(nextChar) || nextChar == '-' || (nextChar == this._decimalSeparator && char.IsDigit(nextChar2)))
                {
                    this._currentIndex--;
                    string text4 = this.ReadNumericLiteral();
                    tokenInfo.Token = Token.NumericLiteral;
                    tokenInfo.Text = text4;
                }
                else
                {
                    if (nextChar == '.')
                    {
                        tokenInfo.Token = Token.Dot;
                        tokenInfo.Text = ".";
                    }
                    else
                    {
                        this._currentIndex--;
                        string text5 = this.ReadUntilNextSpace();
                        tokenInfo = TokenInfo.Illegal;
                        tokenInfo.Text = text5;
                    }
                }
            }
        IL_387:
            tokenInfo.TokenType = this.GetTokenType(tokenInfo.Token);
            return true;
        }
        private char GetNextChar()
        {
            if (this._currentIndex < this._lineLength)
            {
                return this._lineText[this._currentIndex++];
            }
            this._currentIndex++;
            return '\0';
        }
        private string ReadUntilNextSpace()
        {
            StringBuilder stringBuilder = new StringBuilder();
            char nextChar = this.GetNextChar();
            while (!this.IsWhiteSpace(nextChar) && nextChar != '\0')
            {
                stringBuilder.Append(nextChar);
                nextChar = this.GetNextChar();
            }
            this._currentIndex--;
            return stringBuilder.ToString();
        }
        private string ReadKeywordOrIdentifier()
        {
            StringBuilder stringBuilder = new StringBuilder();
            char nextChar = this.GetNextChar();
            while (char.IsLetterOrDigit(nextChar) || nextChar == '_')
            {
                stringBuilder.Append(nextChar);
                nextChar = this.GetNextChar();
            }
            this._currentIndex--;
            return stringBuilder.ToString();
        }
        private string ReadNumericLiteral()
        {
            StringBuilder stringBuilder = new StringBuilder();
            char nextChar = this.GetNextChar();
            this.GetNextChar();
            this._currentIndex--;
            bool flag = true;
            bool flag2 = false;
            while (nextChar != '-' || flag)
            {
                if (nextChar == this._decimalSeparator && !flag2)
                {
                    flag2 = true;
                }
                else
                {
                    if (!char.IsDigit(nextChar))
                    {
                        break;
                    }
                }
                flag = false;
                stringBuilder.Append(nextChar);
                nextChar = this.GetNextChar();
            }
            this._currentIndex--;
            return stringBuilder.ToString();
        }
        private string ReadStringLiteral()
        {
            StringBuilder stringBuilder = new StringBuilder();
            char nextChar = this.GetNextChar();
            stringBuilder.Append(nextChar);
            nextChar = this.GetNextChar();
            bool flag = false;
            while (nextChar != '\0')
            {
                stringBuilder.Append(nextChar);
                if (nextChar == '"')
                {
                    nextChar = this.GetNextChar();
                    if (nextChar != '"')
                    {
                        flag = true;
                        break;
                    }
                    stringBuilder.Append(nextChar);
                }
                nextChar = this.GetNextChar();
            }
            if (flag)
            {
                this._currentIndex--;
                return stringBuilder.ToString();
            }
            return stringBuilder.ToString();
        }
        private string ReadComment()
        {
            StringBuilder stringBuilder = new StringBuilder();
            char nextChar = this.GetNextChar();
            stringBuilder.Append(nextChar);
            stringBuilder.Append(this._lineText.Substring(this._currentIndex));
            this._currentIndex = this._lineLength;
            return stringBuilder.ToString();
        }
        private void EatSpaces()
        {
            while (this.IsWhiteSpace(this.GetNextChar()))
            {
            }
            this._currentIndex--;
        }
        private bool IsWhiteSpace(char c)
        {
            switch (c)
            {
                case '\t':
                case '\v':
                case '\f':
                    {
                        break;
                    }
                case '\n':
                    {
                        goto IL_27;
                    }
                default:
                    {
                        if (c != '\u001a' && c != ' ')
                        {
                            goto IL_27;
                        }
                        break;
                    }
            }
            return true;
        IL_27:
            return c >= '\u0080' && char.GetUnicodeCategory(c) == UnicodeCategory.SpaceSeparator;
        }
        private Token MatchToken(string tokenText)
        {
            string key;
            switch (key = tokenText.ToLower(CultureInfo.InvariantCulture))
            {
                case "and":
                    {
                        return Token.And;
                    }
                case "else":
                    {
                        return Token.Else;
                    }
                case "elseif":
                    {
                        return Token.ElseIf;
                    }
                case "endfor":
                    {
                        return Token.EndFor;
                    }
                case "endif":
                    {
                        return Token.EndIf;
                    }
                case "endsub":
                    {
                        return Token.EndSub;
                    }
                case "endwhile":
                    {
                        return Token.EndWhile;
                    }
                case "for":
                    {
                        return Token.For;
                    }
                case "goto":
                    {
                        return Token.Goto;
                    }
                case "if":
                    {
                        return Token.If;
                    }
                case "or":
                    {
                        return Token.Or;
                    }
                case "step":
                    {
                        return Token.Step;
                    }
                case "sub":
                    {
                        return Token.Sub;
                    }
                case "then":
                    {
                        return Token.Then;
                    }
                case "to":
                    {
                        return Token.To;
                    }
                case "while":
                    {
                        return Token.While;
                    }
            }
            return Token.Identifier;
        }
        private TokenType GetTokenType(Token token)
        {
            switch (token)
            {
                case Token.Illegal:
                    {
                        return TokenType.Illegal;
                    }
                case Token.Comment:
                    {
                        return TokenType.Comment;
                    }
                case Token.StringLiteral:
                    {
                        return TokenType.StringLiteral;
                    }
                case Token.NumericLiteral:
                    {
                        return TokenType.NumericLiteral;
                    }
                case Token.Identifier:
                    {
                        return TokenType.Identifier;
                    }
                case Token.Else:
                case Token.ElseIf:
                case Token.EndFor:
                case Token.EndIf:
                case Token.EndSub:
                case Token.EndWhile:
                case Token.For:
                case Token.Goto:
                case Token.If:
                case Token.Step:
                case Token.Sub:
                case Token.Then:
                case Token.To:
                case Token.While:
                    {
                        return TokenType.Keyword;
                    }
                case Token.And:
                case Token.Equals:
                case Token.Or:
                case Token.Dot:
                case Token.Addition:
                case Token.Subtraction:
                case Token.Division:
                case Token.Multiplication:
                case Token.LeftParens:
                case Token.RightParens:
                case Token.LessThan:
                case Token.LessThanEqualTo:
                case Token.GreaterThan:
                case Token.GreaterThanEqualTo:
                case Token.NotEqualTo:
                case Token.Comma:
                case Token.Colon:
                    {
                        return TokenType.Operator;
                    }
            }
            return TokenType.Illegal;
        }
    }
}
